package com.atguigu.gmall.cart.service.impl;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.cart.entity.CartItem;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.cart.vo.AddCartSuccessVo;
import com.atguigu.gmall.common.auth.UserAuthInfo;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.utils.UserAuthUtils;
import com.atguigu.gmall.feign.product.SkuDetailFeignClient;
import com.atguigu.gmall.product.entity.SkuInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private SkuDetailFeignClient skuDetailFeignClient ;

    @Autowired
    private RedisTemplate<String , String> redisTemplate ;

    @Override
    public AddCartSuccessVo addCart(Long skuId, Integer skuNum) {

        // 构建购物车数据key
        String redisCartKey = buildRedisCartKey() ;

        // 根据skuId查询商品数据
        Result<SkuInfo> skuInfoResult = skuDetailFeignClient.findSkuInfoBySkuId(skuId);
        SkuInfo skuInfo = skuInfoResult.getData();

        // 判断当前的skuId在购物车中是否存在
        Boolean hasKey = redisTemplate.opsForHash().hasKey(redisCartKey, String.valueOf(skuId));
        if(hasKey) {

            String cartItemJSON = redisTemplate.opsForHash().get(redisCartKey, String.valueOf(skuId)).toString();
            CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);
            cartItem.setSkuNum(cartItem.getSkuNum() + skuNum);

            // 单个商品的购买数量最多为10
            Integer itemSkuNum = cartItem.getSkuNum();
            if(itemSkuNum > 10) {
                cartItem.setSkuNum(10);
            }

            cartItem.setSkuPrice(skuInfo.getPrice());
            cartItem.setUpdateTime(new Date());
            redisTemplate.opsForHash().put(redisCartKey , String.valueOf(skuId) , JSON.toJSONString(cartItem));

        }else {

            // 判断购物项数量
            Long size = redisTemplate.opsForHash().size(redisCartKey);
            if(size >= 3) {
                throw new GmallException(ResultCodeEnum.CART_ITEM_COUNT_ERROR) ;
            }

            // 构建购物项数据
            CartItem cartItem = new CartItem() ;
            cartItem.setSkuId(skuId);
            cartItem.setCartPrice(skuInfo.getPrice());
            cartItem.setSkuPrice(skuInfo.getPrice());
            cartItem.setSkuNum(skuNum);
            if(skuNum > 10 ) {
                cartItem.setSkuNum(10);
            }
            cartItem.setImgUrl(skuInfo.getSkuDefaultImg());
            cartItem.setSkuName(skuInfo.getSkuName());
            cartItem.setIsChecked(1);           // 默认选中
            cartItem.setCreateTime(new Date());
            cartItem.setUpdateTime(new Date());

            // 把数据存储到Redis中
            redisTemplate.opsForHash().put(redisCartKey , String.valueOf(skuId) , JSON.toJSONString(cartItem));
        }

        // 构建响应结果
        AddCartSuccessVo addCartSuccessVo = new AddCartSuccessVo() ;
        addCartSuccessVo.setSkuInfo(skuInfo);
        addCartSuccessVo.setSkuNum(skuNum);

        // 判断用户是否操作的是临时购物车，如果是临时购物车设置一个有效期
        UserAuthInfo userAuthInfo = UserAuthUtils.getUserAuthInfo();
        String userId = userAuthInfo.getUserId();
        if(StringUtils.isEmpty(userId)) {       // 未登录
            String userTempCartKey = "cart:info:" + userAuthInfo.getUserTempId() ;
            Long expire = redisTemplate.getExpire(userTempCartKey);
            if(expire < 0) {        // -1(永不过期)
                redisTemplate.expire(userTempCartKey , 30 , TimeUnit.DAYS) ;
            }
        }

        return addCartSuccessVo;
    }

    @Override
    public List<CartItem> cartList() {

        // 购物车数据合并
        UserAuthInfo userAuthInfo = UserAuthUtils.getUserAuthInfo();
        String userId = userAuthInfo.getUserId();
        if(!StringUtils.isEmpty(userId)) {      // 登录成功

            // 用户购物车的数据key
            String userCartKey = "cart:info:" + userId ;

            // 获取用户的临时购物车数据
            String userTempIdCartKey = "cart:info:" + userAuthInfo.getUserTempId() ;
            List<Object> objectList = redisTemplate.opsForHash().values(userTempIdCartKey);
            List<CartItem> userTempCartItemList = objectList.stream().map(obj -> {
                String cartItemJSON = obj.toString();
                CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);
                return cartItem;
            }).collect(Collectors.toList());

            // 判断用户购物车和临时购物车中商品的总数量是否超过3，如果超过了就不允许进行合并
            Stream<Long> userCartStream = redisTemplate.opsForHash().values(userCartKey).stream().map(obj -> {
                String cartItemJSON = obj.toString();
                CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);
                return cartItem.getSkuId();
            });

            Stream<Long> userTempCartItem = userTempCartItemList.stream().map(cartItem -> cartItem.getSkuId());
            long count = Stream.concat(userCartStream, userTempCartItem).distinct().count();
            if( count > 3 ) {
                throw new GmallException(ResultCodeEnum.CART_ITEM_COUNT_ERROR) ;
            }

            // 遍历临时购物车的list集合
            for(CartItem cartItem : userTempCartItemList) {

                // 判断当前的购物项在用户购物车中是否存在，如果不存在直接添加进入，如果存在购买数量进行累加
                Boolean hasKey = redisTemplate.opsForHash().hasKey(userCartKey, String.valueOf(cartItem.getSkuId()));
                if(hasKey) {
                    String userCartItemJSON = redisTemplate.opsForHash().get(userCartKey, String.valueOf(cartItem.getSkuId())).toString();
                    CartItem userCartItem = JSON.parseObject(userCartItemJSON, CartItem.class);
                    userCartItem.setSkuNum(userCartItem.getSkuNum() + cartItem.getSkuNum());
                    Integer skuNum = userCartItem.getSkuNum();
                    if(skuNum > 10) {
                        userCartItem.setSkuNum(10);
                    }
                    redisTemplate.opsForHash().put(userCartKey , String.valueOf(cartItem.getSkuId()) , JSON.toJSONString(userCartItem));
                }else {     // 不存在
                    redisTemplate.opsForHash().put(userCartKey , String.valueOf(cartItem.getSkuId()) , JSON.toJSONString(cartItem));
                }

            }

            // 删除临时购物车
            redisTemplate.delete(userTempIdCartKey) ;

            // 查询用户购物车的数据，进行返回
            return findAllCartItem(userCartKey) ;

        }else {     // 没有登录

            String redisCartKey = buildRedisCartKey();
            return findAllCartItem(redisCartKey) ;

        }
    }

    private List<CartItem> findAllCartItem(String redisKey) {

        List<Object> list = redisTemplate.opsForHash().values(redisKey);
        List<CartItem> cartItemList = list.stream().map(obj -> {
            String cartItemJSON = obj.toString();
            CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);

            // 远程调用service-product微服务的接口查询商品价格数据
            Result<SkuInfo> skuInfoResult = skuDetailFeignClient.findSkuInfoBySkuId(cartItem.getSkuId());
            SkuInfo skuInfo = skuInfoResult.getData();
            cartItem.setSkuPrice(skuInfo.getPrice());       // 实现价格同步
            // 更改Redis中的商品的价格
            redisTemplate.opsForHash().put(redisKey , String.valueOf(cartItem.getSkuId()) , JSON.toJSONString(cartItem));
            return cartItem;
        }).sorted((o1 , o2) -> (int)(o2.getUpdateTime().getTime() - o1.getUpdateTime().getTime())).collect(Collectors.toList());

        return cartItemList ;

    }

    @Override
    public void addToCart(Long skuId, Integer skuNum) {

        // 构建Redis的数据key
        String redisCartKey = buildRedisCartKey();

        // 根据skuId获取购物项数据
        String cartItemJSON = redisTemplate.opsForHash().get(redisCartKey, String.valueOf(skuId)).toString();

        // 将json字符串解析成CartItem对象
        CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);

        // 对购买数量进行变更
        cartItem.setSkuNum(cartItem.getSkuNum() + skuNum);
        Integer itemSkuNum = cartItem.getSkuNum();
        if(itemSkuNum > 10) {
            cartItem.setSkuNum(10);
        }

        // 把数据存储到Redis中
        redisTemplate.opsForHash().put(redisCartKey , String.valueOf(skuId) ,JSON.toJSONString(cartItem));

    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {

        // 构建Redis的数据key
        String redisCartKey = buildRedisCartKey();

        // 根据skuId获取购物项数据
        String cartItemJSON = redisTemplate.opsForHash().get(redisCartKey, String.valueOf(skuId)).toString();

        // 将json字符串解析成CartItem对象
        CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);

        // 设置选中的状态
        cartItem.setIsChecked(isChecked);

        // 把数据存储到Redis中
        redisTemplate.opsForHash().put(redisCartKey , String.valueOf(skuId) ,JSON.toJSONString(cartItem));

    }

    @Override
    public void deleteCart(Long skuId) {

        // 构建Redis的数据key
        String redisCartKey = buildRedisCartKey();

        // 删除操作
        redisTemplate.opsForHash().delete(redisCartKey , String.valueOf(skuId)) ;

    }

    @Override
    public void deleteCheckedCart() {

        // 构建Redis的数据key
        String redisCartKey = buildRedisCartKey();

        // 根据redis的数据key从Redis中获取所有的购物项数据
        List<Object> objectList = redisTemplate.opsForHash().values(redisCartKey);

        // 遍历list集合
        objectList.stream().forEach( obj -> {
            String cartItemJSON = obj.toString();
            CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);
            if(cartItem.getIsChecked() == 1) {
                redisTemplate.opsForHash().delete(redisCartKey , String.valueOf(cartItem.getSkuId())) ;
            }
        });

    }

    @Override
    public List<CartItem> findByUserId() {

        // 获取当前登录用户的id
        UserAuthInfo userAuthInfo = UserAuthUtils.getUserAuthInfo();
        String userId = userAuthInfo.getUserId();

        // 构建redis的数据key
        String cartRedisKey = "cart:info:" + userId ;

        // 查询所有的购物项数据
        List<Object> objectList = redisTemplate.opsForHash().values(cartRedisKey);
        List<CartItem> cartItemList = objectList.stream().map(obj -> {
            String cartItemJson = obj.toString();
            CartItem cartItem = JSON.parseObject(cartItemJson, CartItem.class);
            return cartItem;
        }).filter(cartItem -> cartItem.getIsChecked() == 1).collect(Collectors.toList());

        // 返回
        return cartItemList;
    }

    private String buildRedisCartKey() {

        UserAuthInfo userAuthInfo = UserAuthUtils.getUserAuthInfo();
        String userId = userAuthInfo.getUserId();
        if(!StringUtils.isEmpty(userId)) {      // 用户登录了
            return "cart:info:" + userId ;
        }else {
            return "cart:info:" + userAuthInfo.getUserTempId() ;
        }

    }

}
